package com.huayal.mall.product.controller.web;

import com.huayal.mall.product.entity.CategoryEntity;
import com.huayal.mall.product.service.CategoryService;
import com.huayal.mall.product.vo.CateLog2JsonVo;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Controller
public class IndexController {

    @Autowired
    CategoryService categoryService;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @GetMapping({"/","/home","/index","/index.html"})
    public String  getIndex(Model model){

        //获取一级分类数据
        List<CategoryEntity> categoryEntities=categoryService.getFirstCateGory();
        model.addAttribute("categoryFirst",categoryEntities);

        return "index";
    }

    @ResponseBody
    @GetMapping("index/catalog.json")
    public Map<String, List<CateLog2JsonVo>> getCatelog2JSON(){

        return categoryService.getCatelog2JSON();
    }

    /**
     * 压测专用
     * @return
     */
    @ResponseBody
    @GetMapping("/hello")
    public String getHello(){

        return "hello";
    }

    /**
     * 测试Redisson分布式锁
     * @return
     */
    @ResponseBody
    @GetMapping("/testRedisson")
    public String testRedisson(){

        RLock testLock001 = redissonClient.getLock("testLock001");
        //加锁（若lock()不加参数会30s自动续期【会创建异步任务，自动续期】。为了性能方面考虑最好是加参数，加了参数不会自动续期！但是需要考虑参数时间是否满足业务场景）
//        testLock001.lock();
        testLock001.lock(10, TimeUnit.SECONDS);
        try {
            System.err.println("...加锁成功...处理业务..."+Thread.currentThread());
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            testLock001.unlock();
            System.err.println("释放锁成功..."+Thread.currentThread());
        }

        return "hello";
    }

    /**
     * 读写锁：只有读读锁不会阻塞，其他的（读写、写读、写写都会阻塞）
     * @return
     */
    @GetMapping("/write")
    @ResponseBody
    public String getWrite(){

        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        //加写锁
        RLock rLock = readWriteLock.writeLock();
        String s=null;
        rLock.lock();
        try{
            System.err.println("写操作加锁成功...");
            s= UUID.randomUUID().toString();
            stringRedisTemplate.opsForValue().set("msg",s);
            Thread.sleep(5000);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            rLock.unlock();
            System.err.println("写操作解锁成功...");
        }

        return s;
    }

    @GetMapping("/reader")
    @ResponseBody
    public String getReader(){

        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        RLock rLock = readWriteLock.readLock();
        String msg=null;
        rLock.lock();
        try {
            System.err.println("读操作加锁成功...");
            msg = stringRedisTemplate.opsForValue().get("msg");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();
            System.err.println("读操作解锁成功...");
        }
        return msg;

    }

    /**
     * 闭锁：初始化数量，递减到0则会阻塞
     */
    @GetMapping("/lockDoor")
    @ResponseBody
    public String getLockDoor(){
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        door.trySetCount(5);
        try {
            door.await();//等待数量降低到0
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "关门熄灯...";
    }

    @GetMapping("/goHome/{id}")
    @ResponseBody
    public String goHome(@PathVariable("id") Long id){
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        door.countDown();//这是一个递减的操作
        return id+"下班走人..";
    }

    /**
     * 信号量：Semaphore。类似车停车到停车位，只有停车位都被占有了才会阻塞，若停车一会又开走，只要停车位还有则不会被阻塞（可以控制数量）。经典操作使用：限流，解决生产问题
     * 需要有原本的redis key值而且有值。 比如，key：part value：3
     */
    @GetMapping("/semaphore")
    @ResponseBody
    public String getSemaphore(){
        RSemaphore part = redissonClient.getSemaphore("part");
        boolean b=true;
        try {
//            part.acquire();//获取信号量 阻塞或成功
              b = part.tryAcquire();//获取信号量 返回成功或失败
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "停车成功与否..."+b;
    }

    @GetMapping("/release")
    @ResponseBody
    public String release(){
        RSemaphore part = redissonClient.getSemaphore("part");
        part.release();//释放了线程...
        return "释放了一个车位...";
    }

}
